home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / moupp310 / mouse.doc < prev    next >
Text File  |  1992-08-27  |  42KB  |  1,044 lines

  1.  
  2.                        Mouse++ Version 3.1
  3.  
  4.                Copyright (c)1992 by Carl Moreland
  5.                             06/28/92
  6.  
  7. -----------------------------------------------------------------------
  8.  
  9. What is Mouse++ ?
  10.  
  11.     Mouse++ is a mouse interface class for Borland C++ or TurboC++.
  12. The distributed files are:
  13.  
  14.     mouse.h        header file for Mouse++
  15.     mouse.cpp    source code for Mouse++
  16.     cursor.h    text & graphic cursor definitions
  17.         demo.cpp    text/graphics demo
  18.         mouse.doc    this file
  19.         mouse.his    revision history
  20.  
  21. A demonstration of most of the functions for both text mode and gra-
  22. phics (EGA/VGA) mode is contained in micedemo.cpp.
  23.  
  24.     To incorporate the mouse routines in your program, simply add 
  25. mouse.cpp to your project or make file, and #include mouse.h in any 
  26. module that calls a mouse function.  An instance of the Mouse class 
  27. (there can only be ONE instance) is declared as extern in mouse.h, so 
  28. any file that #includes mouse.h will automatically have access to the 
  29. mouse.  You should NOT declare an instance of the Mouse class in any 
  30. part of your program.  If you intend to change the mouse cursor, then 
  31. you also need to #include cursor.h.
  32.  
  33. -----------------------------------------------------------------------
  34.  
  35. Using the Mouse Class
  36.  
  37.     When you link the mouse code into your program, an instance of 
  38. the mouse class is declared:
  39.  
  40.     Mouse mouse;
  41.  
  42. The constructor Mouse::Mouse() calls the mouse driver reset function 
  43. (all mouse driver functions are called via interrupt 33h) and initia-
  44. lizes the flags exists, enabled, and visible.  exists is set to 1 if a 
  45. mouse was found and should be checked first.  All other mouse class 
  46. functions check exists before issuing interrupt 33h calls and abort if 
  47. it is zero.  enabled is initially zero meaning the mouse is disabled, 
  48. and visible is used by Show() and Hide() to keep track of the cursor 
  49. visibility.  An example of initializing the mouse is:
  50.  
  51.     #include "mouse.h"
  52.  
  53.     main()
  54.     {
  55.       if(mouse.Exists())        // check for mouse
  56.       {
  57.         mouse.Enable();        // enable the mouse
  58.         mouse.Show();        // display the cursor
  59.         ...
  60.       }
  61.     }
  62.  
  63. Again, including  mouse.h automatically creates an instance of the 
  64. class, so all you have to do is start using it.
  65.  
  66.     Once the mouse is initialized, it may be necessary to set some 
  67. parameters based on what video mode is being used.  Strangely, the 
  68. mouse driver uses pixel coordinates for both text and graphics mode, 
  69. with (0,0) being the upper left hand corner of the screen, and (639,199)
  70. being the default lower right hand corner.  This would be correct for 
  71. CGA graphics mode, and for normal 80x25 text mode, this means that each 
  72. character cell is treated as an 8x8 pixel array.  If you are program-
  73. ming for the EGA or VGA as is the norm these days, you will want to 
  74. change the y-limit of 199 for high resolution graphics and 43 or 50 
  75. line text modes.  Failure to do this means that the mouse cursor will 
  76. not move below the 200th line in graphics mode, or the 25th row in text 
  77. mode.  (Older mouse drivers might not support more than 200 lines.  If 
  78. this is the case, you will need to update your mouse driver.)  For 
  79. 640x480 VGA graphics, you need to set the y-limit to (0,479) by calling 
  80. yLimit(0,479).  For 43 or 50 line text mode, the mouse driver still 
  81. treats each character cell as an 8x8 pixel array, so you need to set 
  82. the y-limit to (0,349) or (0,399), respectively.  Since the default 
  83. width of 640 pixels is correct for most video modes, xLimit() is only 
  84. necessary when using SuperVGA graphics.  Both xLimit() and yLimit() can 
  85. also be used to limit the mouse cursor to a small portion of the screen,
  86. such as a menu.
  87.  
  88.     You may want to use a mouse cursor other than the default cur-
  89. sor.  To do this, call the function SetCursor() with the appropriate
  90. cursor name.  Many programs (especially graphics) will use several
  91. different cursors depending on the location of the mouse (such as an
  92. arrow for menus and an i-beam for text) or the particular function being
  93. processed (such as an hourglass for wait).  Several cursors are prede-
  94. fined in the file cursor.h.  To use them, simply include this header
  95. file in whatever module changes the cursor.  For more information on
  96. cursors, see the Mouse Cursors section.
  97.  
  98.     Finally, you may want to set the motion parameters, which in-
  99. clude the mickey-to-pixel ratio and the double-speed threshold.  The
  100. mickey-to-pixel ratio is set by MickToPix() and defines how many mic-
  101. keys it takes to move the mouse 8 pixels.  (A mickey is single count of
  102. mouse motion.  Most mice are 200 "dots-per-inch", which meansthat one
  103. inch of movement results in 200 mickeys.)  If both the x and y parame-
  104. ters are set to 8, then there will be a one-to-one correlation between
  105. mouse motion and cursor motion.  The default values are 8 in the hori-
  106. zontal direction and 16 for the vertical.  The vertical value of 16
  107. means the mouse must be moved twice as far vertically as horizontally
  108. to get the same cursor movement.  This is fine for text mode where the
  109. equivalent screen resolution of 640x200 results in an equivalent pixel
  110. aspect ratio of 2.4-to-1.  In EGA/VGA graphics mode the y-direction
  111. will seem noticeably slower, particularly for 640x480 which has an
  112. equivalent pixel aspect ratio of 1-to-1.  A vertical ratio of 8 will
  113. cure this.  The lower the ratio, the farther the cursor will move for a
  114. given mouse movement. Setting either ratio lower than 8 means that the
  115. cursor cannot be located on every pixel.  For example, setting the ra-
  116. tio to 4 will cause the cursor to move 2 pixels for every mickey.  The
  117. double-speed threshold is set by a call to SetSpeedThreshold().  When
  118. the speed of the mouse (in mickeys per second) exceeds the speed para-
  119. meter passed to SetSpeedThreshold(), the motion speed of the cursor
  120. will double.  A complete initialization might look like this:
  121.  
  122.     #include "mouse.h"
  123.     #include "cursor.h"
  124.  
  125.     main()
  126.     {
  127.       { initialize screen };
  128.       if(mouse.Exists())
  129.       {
  130.         mouse.SetCursor(cross);
  131.         mouse.yLimit(0,479);    // VGA 640x480
  132.         mouse.MickToPix(8,8);
  133.         mouse.SetSpeedThreshold(32);
  134.         mouse.Enable();
  135.         mouse.Show();
  136.         ...
  137.       }
  138.     }
  139.  
  140.     The mouse should be reset before your program terminates so
  141. that the calling program does not inherit any strange parameters.  This
  142. is particularly true of the event handler.  Because it is an interrupt
  143. routine, failure to reset the mouse could lead to a system crash if the
  144. handler is still pointing to the address of what used to be your hand-
  145. ler routine.  The destructor Mouse::~Mouse() first resets the mouse
  146. status by calling function 00h, and then restores the original event
  147. handler with function 14h.
  148.  
  149. -----------------------------------------------------------------------
  150.  
  151. Reading the Mouse
  152.  
  153.     Most of the standard mouse functions stuff any return values
  154. directly into the class variables and have a return type void.  You can
  155. then use the appropriate inline function to read the required private
  156. variable.  To check for the mouse position, for instance, you would
  157. call Position() followed by either xPos() or yPos(), or both, such as:
  158.  
  159.     for(;;)
  160.     {
  161.       mouse.Position();
  162.       if(mouse.xPos() > 320 || mouse.yPos() > 100)
  163.         do_something();
  164.     }
  165.  
  166. This method has the advantage of capturing both the x and y positions
  167. with a single function call, and those variables can then be read at
  168. your leisure.  However, we generally don't care where the mouse is
  169. located unless a button event that we are looking for has occurred.
  170. Position() also returns the status of the mouse buttons, so we can also
  171. check them:
  172.  
  173.     for(;;)
  174.     {
  175.       mouse.Position();
  176.       if(mouse.LB_Dn())        // check for left button down
  177.       {
  178.         if(mouse.xPos() > 320 || mouse.yPos() > 100)
  179.           do_something();
  180.       }
  181.       else
  182.         do_something_else();
  183.     }
  184.  
  185. This loop will continuously check to see if the left button has been
  186. pressed.  If the do_something_else() code is slow then there is a pos-
  187. sibility that a button press could be missed since Position() returns
  188. the real-time status of the mouse.  That is, during execution of the
  189. do_something_else() code, the mouse button could be pressed and re-
  190. leased and Position() would not capture it.  The functions Pressed()
  191. and Released() are best suited for checking for a button event because
  192. they will return the button status since the last time they were called.
  193. For example, this code
  194.  
  195.     for(;;)
  196.     {
  197.       if(mouse.Pressed(LEFTBUTTON))
  198.       {
  199.         if(mouse.xPos() > 320 || mouse.yPos() > 100)
  200.         do_something();
  201.       }
  202.       else
  203.         do_something_else();
  204.     }
  205.  
  206. is guaranteed to capture a button press even if the do_something_else()
  207. code is slow to execute.  Since Pressed() and Released() also return
  208. the cursor position, a separate call to Position() is not necessary.
  209.  
  210.     In using the mouse, it is often necessary to know if the cursor
  211. is located within a certain area of the screen.  For example, in a menu
  212. interface, you want to know if the cursor is located on a menu selec-
  213. tion when a mouse button is clicked.  The function InBox() adds this
  214. capability.  The parameters passed describe the upper left and lower
  215. right corners of the box.  The return value is 1 if the cursor is in
  216. the box, 0 if not.  Therefore, the code
  217.  
  218.     if(mouse.InBox(40,40,100,100))
  219.  
  220. will be true if the mouse cursor is in a box with corners (40,40) and
  221. (100,100).  Like other mouse functions, the coordinates are pixels,
  222. even if the screen is in text mode.
  223.  
  224.     In some cases you may want to hide the cursor if it falls in-
  225. side a certain area.  The mouse driver provides such a function which,
  226. in my opinion, has two drawbacks.  Function 10h defines an exclusion
  227. window in which the mouse cursor will turn itself off.  However, the
  228. programmer must then manually turn the cursor back on once it is out-
  229. side the exclusion area, and this requires continuously checking the
  230. mouse position, such as:
  231.  
  232.     for(;;)
  233.     {
  234.       mouse.Exclude(40,40,100,100);
  235.       do_some_processing();
  236.       if(!mouse.InBox(40,40,100,100))
  237.         mouse.show();
  238.     }
  239.  
  240. The other problem with function 10h is that it only looks at the hot
  241. spot when checking the cursor's position, so part of the cursor could
  242. enter the exclusion area before the hot spot.  The whole point of de-
  243. fining an exclusion area is to turn the cursor off if it enters the
  244. defined area.  The Mouse++ Exclude() function is based on the InBox()
  245. function, taking into account the hot spot location and cursor visi-
  246. bility.
  247.  
  248.     Finally, if your program is performing a time-consuming task in
  249. which mouse input is not needed, you may want to disable the mouse.  If
  250. the mouse is not disabled, the user might become frustrated with a mouse
  251. that does not respond, and the event buffer could become filled with
  252. useless events.  Calling the function Disable() will turn the mouse off
  253. and disable the interrupt handler.  The mouse and interrupt handler are
  254. re-enabled with the next call to Enable(), although the mouse cursor
  255. must be turned on with an explicit call to Show():
  256.  
  257.     ...
  258.     mouse.Disable();
  259.     do_some_long_processing();
  260.     mouse.Enable();
  261.     mouse.Show();
  262.     ...
  263.  
  264. -----------------------------------------------------------------------
  265.  
  266. Mouse Cursors
  267.  
  268.     SetCursor() sets the graphics cursor shape.  The cursor is ini-
  269. tially set to the familiar upper left pointing arrow by the mouse
  270. driver.  A graphics cursor is 16x16 pixels in size and moves in single
  271. pixel increments.  It is defined by a screen mask (background), an over-
  272. lying cursor mask (foreground), and a hot spot.  Since the cursor is
  273. 16x16 pixels, a hot spot must be defined so that a unique pixel posi-
  274. tion can be determined for the cursor.  The hot spot has x and y values
  275. with valid ranges of 0 to 15.
  276.  
  277.     The two masks determine how the screen will appear where the
  278. cursor is located.  The screen mask is first ANDed with the screen
  279. pixels, and the cursor mask is then XORed with the resulting screen.
  280. If a screen mask bit is 0 it will set the underlying screen pixel to 0
  281. (black), and if the screen mask bit is 1 the pixel color will not
  282. change.  A cursor mask bit of 0 does nothing, and a cursor mask bit of
  283. 1 will invert the underlying pixel color.  Since the masks have only
  284. values of 1 or 0 for each pixel location, but each pixel can have a
  285. color, you cannot achieve complete control of the cursor color.  The
  286. two basic choices are a black and white cursor where the screen mask
  287. bits are 0, or a cursor that inverts the screen colors where the screen
  288. mask bits are 1.
  289.  
  290.     Figure 1 shows the default cursor as an example.  The screen
  291. mask alone will set the screen pixels to black for the bits that are 0,
  292. creating a black arrow.  The cursor mask bits that are 1 will then in-
  293. vert the screen color, meaning black will become white.  If you lay the
  294. cursor mask directly over the screen mask, you will notice that the
  295. screen mask arrow extends one pixel beyond the cursor mask arrow.   Be-
  296. cause a screen mask bit 0 will create a black background for the cursor
  297. mask, this has the effect of putting a one pixel black border around
  298. the cursor.  The reason for doing this is to make the cursor visible
  299. even where the screen is white.  Making the screen mask bits all 1's so
  300. that the cursor XOR's with the underlying screen is useful in creating
  301. a CAD cursor (such as a "+" or a "x") that must be one pixel wide.  The
  302. best way to get a better understanding of the graphics cursor is to try
  303. some out.  cursor.h defines several graphics cursors.
  304.  
  305. -----------------------------------------------------------------------
  306.  
  307.     0011111111111111    0000000000000000
  308.     0001111111111111    0100000000000000
  309.     0000111111111111    0110000000000000
  310.     0000011111111111    0111000000000000
  311.     0000001111111111    0111100000000000
  312.     0000000111111111    0111110000000000
  313.     0000000011111111    0111111000000000
  314.     0000000001111111    0111111100000000
  315.     0000000000111111    0111111110000000
  316.     0000000000011111    0111111111000000
  317.     0000000111111111    0111110000000000
  318.     0001000011111111    0100011000000000
  319.     0011000011111111    0000011000000000
  320.     1111100001111111    0000001100000000
  321.     1111100001111111    0000001100000000
  322.     1111110000111111    0000000110000000
  323.  
  324.       Screen Mask          Cursor Mask
  325.  
  326. Figure 1: Example graphics cursor
  327. -----------------------------------------------------------------------
  328.  
  329.     The graphics mask pair are defined together in a single array
  330. of type unsigned integer.  For clarity, comment fields were added in
  331. cursor.h to show what the masks will actually produce.  This is helpful
  332. not only in identifying what a cursor looks like, but also in designing
  333. new cursors.  Since the graphics cursor is a 16x16 pixel image, it also
  334. requires a hot spot for determining the exact position of the mouse.
  335. The hot spot and the mask array are combined in the structure
  336. GraphicsCursor (defined in mouse.h), which must be static.  The cursor
  337. structure can then be passed as a unit to SetCursor().
  338.  
  339.     SetCursor() can also set the text cursor type and shape.  There
  340. are two cursor types in text mode.  The hardware cursor places the nor-
  341. mal video cursor (the cursor you see even without a mouse) under the
  342. control of the mouse.  The software cursor is independent of the video
  343. cursor and behaves similarly to the graphics cursor.  The software cur-
  344. sor is used in most applications so that the user is presented with the
  345. normal video cursor for typing and a mouse cursor for menu selection.
  346. The cursor type - 0 for software, 1 for hardware - is part of the
  347. TextCursor structure.
  348.  
  349.     Like the graphics cursor, the text software cursor also re-
  350. quires a screen and cursor mask, but no hot spot since the cursor al-
  351. ways takes up a whole character cell, regardless of where the mouse
  352. cursor is actually positioned in that cell.  (If a hardware cursor is
  353. implemented, the starting and ending scan lines for the cursor are
  354. required.)  The two masks operate only on a character cell, not a 16x16
  355. pixel array.  Each cell consists of a one-byte character value and a
  356. one-byte character attribute (which sets the foreground and background
  357. colors), so the masks must each be two bytes long.  The upper byte
  358. masks the attribute, and the lower byte masks the character.  Like the
  359. graphics masks, the screen mask is XORed with the underlying character
  360. cell, and the cursor mask is ANDed with the resulting value.  The dif-
  361. ference is that in text mode, both the character value and its color
  362. can be changed, whereas in graphics mode, the pixel colors cannot be
  363. controlled.
  364.  
  365.     To get a better understanding of what the masks will do, we
  366. need to look at an example of a screen character:
  367.  
  368.       6B24h = 0110 1011 0010 0100 b
  369.               |--- ---- ---------
  370.               | |   |       |__ character value
  371.               | |   |__________ foreground color
  372.               | |______________ background color
  373.               |________________ blinking bit (1=blinking)
  374.  
  375. This value will display a '$' (24h) with a background color of brown
  376. (06h) and a foreground color of lightcyan (0Bh = 11).  With the text
  377. cursor, we can mask each bit of the character and attribute, so not
  378. only can we set the mouse cursor character, but we can also control the
  379. foreground and background colors (and even blinking).  The cursor masks
  380. default to a reverse box, which is
  381.  
  382.     Screen Mask = 77FFh = 0111 0111 1111 1111 b
  383.     Cursor Mask = 7700h = 0111 0111 0000 0000 b
  384.  
  385. The first byte of the screen mask, 77h in this example, is ANDed with
  386. the underlying characters attribute. The first 7h is ANDed with the
  387. background color so that all colors but the blinking bit are passed
  388. through.  Masking the blinking bit to 0 will allow the mouse cursor to
  389. rest on a blinking character without itself blinking.  The second 7h is
  390. ANDed with the foreground color so that those colors are also passed,
  391. except that the high intensity colors will be converted to low inten-
  392. sity.  The FFh also passes the screen character.  In the cursor mask,
  393. the 77h will invert both the foreground and background colors, while
  394. the 00h creates an "empty" character, which is a character cell with
  395. nothing in it (a box).
  396.  
  397.     If you want to create a cursor with a particular character and
  398. color, you would set the screen mask to 0000h and the cursor mask to
  399. whatever color and character values desired.  For example,
  400.  
  401.     Screen Mask = 0000h = 0000 0000 0000 0000b
  402.     Cursor Mask = 0F23h = 0000 1111 0010 0011b
  403.  
  404. will set the cursor character to a '#' with a background color of black
  405. and a foreground color of white.  More complex combinations are possi-
  406. ble, such as setting the cursor's foreground color to a constant value
  407. but allowing the screen's background color to show through.  Again, the
  408. best way to understand it is to try it, and cursor.h defines several
  409. text cursors.
  410.  
  411. -----------------------------------------------------------------------
  412.  
  413. The Event Handler
  414.  
  415.     There is another way to capture mouse events.  The mouse event 
  416. handler is similar to a TSR program in that it can be set up to capture 
  417. events in background.  The handler can be set to trigger off any combi-
  418. nation of mouse events (Table 1), and can then execute any user code, 
  419. providing it does not issue a DOS or I/O call.  However, since the main 
  420. program is suspended during the event handler execution, the handler 
  421. code should be fast so it does not to noticeably slow down the main pro-
  422. gram.  When an event occurs, certain mouse information is automatically 
  423. placed in the registers for the handler to use.  The routine Save() can 
  424. be used to stuff these parameters into the Mouse class for later use.  
  425. Any event handler routines you write must be declared as an interrupt 
  426. type and terminate with a far return.  The macro EventExit() provides 
  427. the proper exit code and should be the last statement in the handler 
  428. function:
  429.  
  430.     void interrupt my_handler()
  431.     {
  432.       mouse.Save();
  433.       do_something();
  434.       EventExit();
  435.     }
  436.  
  437.     Installing an event handler is accomplished with the function 
  438. InstallHandler():
  439.     
  440.     #include "mouse.h"
  441.  
  442.     void interrupt my_handler();
  443.     
  444.     main()
  445.     {
  446.       unsigned char eventmask = LB_PRESSED || LB_RELEASED;
  447.       if(mouse.Exists())
  448.       {
  449.         mouse.InstallHandler(eventmask, myhandler);
  450.         mouse.Show();
  451.         ...
  452.       }
  453.     }
  454.  
  455. eventmask determines which mouse events will trigger the event handler. 
  456. In the example above, the handler will execute whenever the left button 
  457. is pressed or released.  Because the event handler should be kept as 
  458. small as possible, you normally only want to call Save() for storing 
  459. the mouse information and then exit.  The mouse class provides such a
  460. handler by default if you do not specify a handler function name in the 
  461. call to InstallHandler():
  462.  
  463.     main()
  464.     {
  465.       if(mouse.Exists())
  466.       {
  467.         mouse.InstallHandler(LB_PRESSED || LB_RELEASED);
  468.         mouse.Show();
  469.         ...
  470.       }
  471.     }
  472.  
  473. There might be some cases where you want the handler to do more, such 
  474. as when the program is waiting for user input and not doing much other 
  475. processing.  In such cases you may want to load different handlers, 
  476. depending on what the program is doing.  A more functional handler can 
  477. be loaded for pulldown menus, for instance, and a bare-bones handler 
  478. (or none at all) can be installed in speed critical areas where the 
  479. mouse has little use.
  480.  
  481.     The Save() function called by the event handler stores the 
  482. mouse information in a buffer instead of writing it directly into the 
  483. class.  This allows events to be captured even while your program is 
  484. busy doing something else.  (The keyboard has a similar buffer that 
  485. provides type-ahead capability.)  To get the event information out of 
  486. the buffer, you must call the function GetEvent():
  487.  
  488.     for(;;)
  489.     {
  490.       mouse.GetEvent();        // get an event from the buffer
  491.       if(mouse.LB_Dn())        // check for left button down
  492.       {
  493.         if(mouse.xPos() > 320 || mouse.yPos() > 100)
  494.           do_something();
  495.       }
  496.       else
  497.         do_something_else();
  498.     }
  499.  
  500.     Properly used, event handlers can add a whole new dimension to 
  501. a mouse driven interface.  However, there are some pitfalls to avoid.  
  502. If you set the event mask to trigger on mouse movement, then the hand-
  503. ler will execute quite often (every time the mouse is moved) and could 
  504. noticeably slow program execution during periods of heavy computation.
  505. Usually, the only reason to trigger on movement is to update a motion 
  506. counter such as in the demo program, or to have cursors that dynami-
  507. cally change depending on the cursor position such as in a GUI.  As 
  508. mentioned before, the handler should not issue a DOS, ROM, or I/O call. 
  509. The handler, like a TSR, is an interrupt routine that runs while the 
  510. main DOS program is suspended.  DOS is not a re-entrant operating sys-
  511. tem and issuing such a call will usually crash the system.  Also, some 
  512. standard C library routines make use of these system functions (such as 
  513. printf()), so often the only way of finding out is by trial and reboot.
  514.  
  515. -----------------------------------------------------------------------
  516.     0x01    MOUSE_MOVED
  517.     0x02    LB_PRESSED
  518.     0x04    LB_RELEASED
  519.     0x08    RB_PRESSED
  520.     0x10    RB_RELEASED
  521.     0x20    CB_PRESSED
  522.     0x40    CB_RELEASED
  523.     
  524.     Table 1: Mouse events
  525. -----------------------------------------------------------------------
  526.  
  527. A Demonstration
  528.  
  529.     micedemo.cpp is a demo program that utilizes most of the mouse 
  530. functions described.  main() installs the event handler, runs a text 
  531. mode demo, and a graphics mode demo.  The event mask is FFh which will 
  532. trigger the handler on any mouse event.  Since that includes mouse 
  533. movement, the default handler that only calls Save() is used to store 
  534. the parameters and keep execution time to a minimum.
  535.  
  536.     Both demos (textdemo() and graphicdemo()) call a function that 
  537. draws the screen and another that processes mouse events.  textscreen() 
  538. assumes a color video card and draws a screen with eight different 
  539. characters and colors to demonstrate how the cursor masks work.  Notice 
  540. that the loop that draws the screen actually writes 50 lines of video 
  541. even though the demo starts out with 25 lines.  A graphical represen-
  542. tation of a three-button mouse is drawn to show the cursor position and 
  543. button status.  After calling textscreen(), textdemo() prints the infor-
  544. mation from the mouse.Info structure to the screen.  The mouse y-limit 
  545. is set to full screen (25 lines, which is the default) and the cursor 
  546. is turned on with Show().  nexttdemo() is the processing loop for text 
  547. mode and is called with the name of text cursor structure and a title 
  548. string.  nexttdemo() is called with several different cursors and also 
  549. for 43/50 line mode.
  550.  
  551.     nexttdemo() first sets the text cursor and prints the title 
  552. string.  It then runs a loop that process mouse events.  A counter that 
  553. shows the mouse position calls xPos() and yPos() which read variables 
  554. that are continuously updated by the event handler via GetEvent().  
  555. Button status is also checked and displayed.  Released() is called to 
  556. check for a left button release event which will terminate the loop if 
  557. the cursor is inside the [Next] box at the time of release.  The loop 
  558. will also be terminated if the left button is double-clicked anywhere 
  559. on the screen.  If the right button is double-clicked, the mouse is 
  560. disabled until any keyboard key is pressed.  Pressing the <Ctrl> key 
  561. and the left button will set the global flag "done" which exits the 
  562. rest of the text demo and proceeds with the graphics demo.
  563.  
  564.     graphicdemo() works the same way as textdemo().  In addition to trying several cursors, it also tests different mickey-to-pixel ratios.  Notice that the ratio of 2 for the jet cursor will cause the cursor to locate on every fourth pixel as it moves across the screen.  graphicscreen() paints several background colors as well as black and white boxes in the center.  These boxes demonstrate the use of the cursor border created by the screen mask.  A graphical representation of a three-button mouse is again drawn to show the cursor position and button status.  nextgdemo() sets the graphics cursor and then processes mouse events, checking the position and button status.  
  565.  
  566.     The variables LBDN, CBDN, and RBDN are used to compare the cur-
  567. rent button status against the previous button status.  The color of 
  568. the screen buttons are then toggled if any button status has changed.  
  569. (This method is used to avoid screen paints in every pass through the 
  570. loop if the button status has not changed.  This is not necessary in 
  571. text mode because screen writes are much faster.)  Buttons are checked 
  572. for multi-clicks (up to four) and the color of the screen buttons will 
  573. reflect this.  Finally, we check for a left button release and see if 
  574. the cursor is in the [Next] box, a left button triple-click, and a 
  575. <Ctrl>-left button, and exit if so.
  576.  
  577. -----------------------------------------------------------------------
  578.  
  579. The Mouse++ Functions
  580.  
  581. -----------------------------------------------------------------------
  582. Mouse::Exists()
  583.  
  584. Syntax:     unsigned char Exists(void)
  585.  
  586. Description:    Returns the value of an internal flag that is set by
  587.         the Mouse constructor.
  588.  
  589. Return Value:    1 if a mouse was found, 0 otherwise.
  590.  
  591. -----------------------------------------------------------------------
  592. Mouse::Visible()
  593.  
  594. Syntax:     unsigned char Visible(void)
  595.  
  596. Description:    Returns the status of the cursor visibility.
  597.  
  598. Return Value:    1 if the cursor is visible, 0 otherwise.
  599.  
  600. -----------------------------------------------------------------------
  601. Mouse::Buttons()
  602.  
  603. Syntax:     unsigned char Buttons(void)
  604.  
  605. Description:    Returns the number of buttons for the mouse
  606.  
  607. Return Value:    2 for a 2-button mouse, 3 for a 3-button mouse.
  608.  
  609. -----------------------------------------------------------------------
  610. Mouse::Button()
  611.  
  612. Syntax:     unsigned char Button(void)
  613.  
  614. Description:    Returns the status of the mouse buttons and shift keys
  615.         that is stored internal to the Mouse class. Call
  616.         Position() before using this function to insure an
  617.         accurate value, or when using the event handler call
  618.         GetEvent().
  619.  
  620. Return Value:    A mask corresponding to the status of the mouse buttons
  621.         and the shift keys (down=1, up=0):
  622.         -------------------------------------------------------
  623.         0x01    Left button
  624.         0x02    Right button
  625.         0x04    Center button
  626.         0x08    Either shift key
  627.         0x10    Right shift key
  628.         0x20    Left shift key
  629.         0x40    Alt key
  630.         0x80    Ctrl key
  631.  
  632. -----------------------------------------------------------------------
  633. Mouse::Enable()
  634.  
  635. Syntax:     void Enable(void)
  636.  
  637. Description:    Enables the mouse. This function must be called before
  638.         the mouse can be used for the first time, or after a
  639.         call to Disable(). A separate call to Show() is neces-
  640.         sary to display the cursor.
  641.  
  642. Return Value:    None.
  643.  
  644. -----------------------------------------------------------------------
  645. Mouse::Disable()
  646.  
  647. Syntax:     void Disable(void)
  648.  
  649. Description:    Disables the mouse and hides the cursor. If an event
  650.         handler has been installed, it is disabled and the
  651.         event buffer and multi-click buffer are cleared.
  652.  
  653. Return Value:    None.
  654.  
  655. -----------------------------------------------------------------------
  656. Mouse::Show()
  657.  
  658. Syntax:     void Show(void)
  659.  
  660. Description:    Turns on the mouse cursor.
  661.  
  662. Return Value:    None. Sets the internal visible flag to 1.
  663.  
  664. -----------------------------------------------------------------------
  665. Mouse::Hide()
  666.  
  667. Syntax:     void Hide(void)
  668.  
  669. Description:    Turns off the mouse cursor. All other mouse functions
  670.         will continue to operate. You should hide the cursor
  671.         prior to any screen writes to avoid having the mouse
  672.         restore an incorrect background.
  673.  
  674. Return Value:    None. Sets the internal visible flag to 0.
  675.  
  676. -----------------------------------------------------------------------
  677. Mouse::Position()
  678.  
  679. Syntax:     void Position(void)
  680.  
  681. Description:    Reads the cursor position and saves the coordinates
  682.         in internal variables. Use xPos() & yPos() to read
  683.         the internal variables. This function is not intended
  684.         for use with the event handler.
  685.  
  686. Return Value:    None. Sets internal class position variables and button
  687.         status.
  688.  
  689. -----------------------------------------------------------------------
  690. Mouse::xPos()
  691.  
  692. Syntax:     int xPos(void)
  693.  
  694. Description:    Returns the x-position of the mouse cursor that is
  695.         stored internal to the Mouse class. Call Position()
  696.         before using this function to insure an accurate
  697.         value, or when using the event handler call GetEvent().
  698.  
  699. Return Value:    An integer that corresponds to the pixel location of
  700.         the cursor, even if the screen is in text mode.
  701.  
  702. -----------------------------------------------------------------------
  703. Mouse::yPos()
  704.  
  705. Syntax:     int yPos(void)
  706.  
  707. Description:    Returns the y-position of the mouse cursor that is
  708.         stored internal to the Mouse class. Call Position()
  709.         before using this function to insure an accurate
  710.         value, or when using the event handler call GetEvent().
  711.  
  712. Return Value:    An integer that corresponds to the pixel location of
  713.         the cursor, even if the screen is in text mode.
  714.  
  715. -----------------------------------------------------------------------
  716. Mouse::Motion()
  717.  
  718. Syntax:     void Motion(void)
  719.  
  720. Description:    Reads the internal motion counters which give the dis-
  721.         tance (in mickeys) the mouse has moved since the last
  722.         call to this function, and stores the values in class
  723.         variables. Use xCount() & yCount() to read these vari-
  724.         ables. This function is not intended for use with the
  725.         event handler.
  726.  
  727. Return Value:    None.
  728.  
  729. -----------------------------------------------------------------------
  730. Mouse::xCount()
  731.  
  732. Syntax:     int xCount(void)
  733.  
  734. Description:    Returns the distance the mouse has moved in the x-
  735.         direction. The distance is in mickeys, which may or may
  736.         not be the same as pixels, depending on the mickey-to-
  737.         pixel ratio. This function is useful for seeing if the
  738.         mouse has moved.
  739.  
  740. Return Value:    An integer that corresponds to the x distance in mic-
  741.         keys, regardless of screen mode.
  742.  
  743. -----------------------------------------------------------------------
  744. Mouse::yCount()
  745.  
  746. Syntax:     int yCount(void)
  747.  
  748. Description:    Returns the distance the mouse has moved in the y-
  749.         direction. The distance is in mickeys, which may or may
  750.         not be the same as pixels, depending on the mickey-to-
  751.         pixel ratio. This function is useful for seeing if the
  752.         mouse has moved.
  753.  
  754. Return Value:    An integer that corresponds to the y distance in mic-
  755.         keys, regardless of screen mode.
  756.  
  757. -----------------------------------------------------------------------
  758. Mouse::Move()
  759.  
  760. Syntax:     void Move(int x, int y)
  761.  
  762. Description:    Moves the cursor to a new position. x & y must be
  763.         pixel coordinates even if the screen is in text mode.
  764.  
  765. Return Value:    None.
  766.  
  767. -----------------------------------------------------------------------
  768. Mouse::Pressed()
  769.  
  770. Syntax:     int Pressed(int mbutton)
  771.  
  772. Description:    In manual mode, this checks to see if mbutton has been
  773.         pressed since the last call to this command. In event
  774.         driven mode, this checks to see if the current event
  775.         was triggered by mbutton pressed. mbutton can be 0
  776.         (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  777.  
  778. Return Value:    1 if mbutton has a pressed event, 0 otherwise.
  779.  
  780. -----------------------------------------------------------------------
  781. Mouse::Released()
  782.  
  783. Syntax:        int Released(int mbutton)
  784.  
  785. Description:    In manual mode, this checks to see if mbutton has been
  786.         released since the last call to this command. In event
  787.         driven mode, this checks to see if the current event
  788.         was triggered by mbutton released. mbutton can be 0
  789.         (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  790.  
  791. Return Value:    1 if mbutton has a released event, 0 otherwise.
  792.  
  793. -----------------------------------------------------------------------
  794. Mouse::LB_Dn()
  795.  
  796. Syntax:     unsigned char LB_Dn(void)
  797.  
  798. Description:    Returns the status of the left button.
  799.  
  800. Return Value:    1 if the left button is pressed, 0 otherwise.
  801.  
  802. -----------------------------------------------------------------------
  803. Mouse::RB_Dn()
  804.  
  805. Syntax:     unsigned char RB_Dn(void)
  806.  
  807. Description:    Returns the status of the right button.
  808.  
  809. Return Value:    1 if the right button is pressed, 0 otherwise.
  810.  
  811. -----------------------------------------------------------------------
  812. Mouse::CB_Dn()
  813.  
  814. Syntax:     unsigned char CB_Dn(void)
  815.  
  816. Description:    Returns the status of the center button.
  817.  
  818. Return Value:    1 if the center button is pressed, 0 otherwise.
  819.  
  820. -----------------------------------------------------------------------
  821. Mouse::xLimit()
  822.  
  823. Syntax:     void xLimit(int min, int max)
  824.  
  825. Description:    Sets the limit that the cursor can move in the x-
  826.         direction. min & max must be pixel values even if the
  827.         screen is in text mode.
  828.  
  829. Return Value:    None.
  830.  
  831. -----------------------------------------------------------------------
  832. Mouse::yLimit()
  833.  
  834. Syntax:     void yLimit(int min, int max)
  835.  
  836. Description:    Sets the limit that the cursor can move in the y-
  837.         direction. min & max must be pixel values even if the
  838.         screen is in text mode.
  839.  
  840. Return Value:    None.
  841.  
  842.  
  843. -----------------------------------------------------------------------
  844. Mouse::GetVideoPage(void);
  845.  
  846. Syntax:     int GetVideoPage(void)
  847.  
  848. Description:    Gets the video page number for which the mouse cursor
  849.         is currently active. This may or may not be the same
  850.         as the video page that is currently being displayed on
  851.         the screen.
  852.  
  853. Return Value:    The number of the mouse cursor's current video page.
  854.  
  855. -----------------------------------------------------------------------
  856. Mouse::SetVideoPage(void);
  857.  
  858. Syntax:        void SetVideoPage(int page);
  859.  
  860. Description:    Sets the video page for which the mouse cursor will be
  861.         active. Normally this will be the same as the displayed
  862.         video page but it does not have to be.
  863.  
  864. Return Value:    None.
  865.  
  866. -----------------------------------------------------------------------
  867. Mouse::SetCursor()
  868.  
  869. Syntax:     void SetCursor(TextCursor& cursor)
  870.         void SetCursor(GraphicsCursor& cursor)
  871.  
  872. Description:    Sets the text cursor as described by the TextCursor
  873.         structure or the graphics cursor as described by the
  874.                 GraphicsCursor structure.
  875.  
  876. Return Value:    None.
  877.  
  878. -----------------------------------------------------------------------
  879. Mouse::MickToPix()
  880.  
  881. Syntax:     void MickToPix(int horiz, int vert)
  882.  
  883. Description:    Sets the mickey-to-pixel ratio. A mickey is a motion
  884.         signal sent by the mouse and occurs every 1/200th inch
  885.         for most mice. horiz passes the number of mickeys re-
  886.         quired for an 8 pixel horizontal movement, and vert
  887.         passes the number of mickeys required for an 8 pixel
  888.         vertical movement. The constructor sets these to 8 and
  889.         16, respectively.
  890.  
  891. Return Value:    None.
  892.  
  893. -----------------------------------------------------------------------
  894. Mouse::SetSpeedThreshold()
  895.  
  896. Syntax:     void SetSpeedThreshold(unsigned speed)
  897.  
  898. Description:    Sets the threshold at which the cursor speed doubles.
  899.         speed is in mickeys-per-second and defaults to 64.
  900.         Supposedly, this function is only available for Logi-
  901.         tech mice.
  902.  
  903. Return Value:    None.
  904.  
  905. -----------------------------------------------------------------------
  906. Mouse::SetClickThreshold()
  907.  
  908. Syntax:     void SetClickThreshold(unsigned time)
  909.  
  910. Description:    Sets the threshold at which sequential clicks are regi-
  911.         stered as multi-clicks. time is in milliseconds and de-
  912.         faults to 250.
  913.  
  914. Return Value:    None.
  915.  
  916. -----------------------------------------------------------------------
  917. Mouse::MultiClick()
  918.  
  919. Syntax:     int MultiClick(int mbutton)
  920.  
  921. Description:    Checks for multi-clicks of button mbutton. mbutton can
  922.         be 0 (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  923.  
  924. Return Value:    Current number of multi-clicks.
  925.  
  926. -----------------------------------------------------------------------
  927. Mouse::DoubleClick()
  928.  
  929. Syntax:     int DoubleClick(int mbutton)
  930.  
  931. Description:    Checks for double-clicks of button mbutton. mbutton can
  932.         be 0 (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  933.  
  934. Return Value:    1 if mbutton has been double-clicked, 0 otherwise.
  935.  
  936. -----------------------------------------------------------------------
  937. Mouse::ClearClick()
  938.  
  939. Syntax:     void ClearClick(int mbutton)
  940.  
  941. Description:    Resets the multi-click status of mbutton. mbutton can
  942.         be 0 (LEFTBUTTON), 1 (RIGHTBUTTON), or 2 (CENTERBUTTON).
  943.  
  944. Return Value:    None.
  945.  
  946. -----------------------------------------------------------------------
  947. Mouse::InBox()
  948.  
  949. Syntax:     int InBox(int left, int top, int right, int bottom)
  950.  
  951. Description:    Checks if the mouse cursor is located within a rec-
  952.         tangle. Rectangle limits should be in pixels regardless
  953.         of screen mode.
  954.  
  955. Return Value:    1 if the cursor is in the rectangle, 0 otherwise.
  956.  
  957. -----------------------------------------------------------------------
  958. Mouse::Exclude()
  959.  
  960. Syntax:     void Exclude(int left, int top, int right, int bottom)
  961.  
  962. Description:    Sets up an exclusion area in which the mouse cursor
  963.         automatically turns itself off. This is not the same as
  964.         the exclude function that is built into the mouse, and
  965.         must be continuously called in a loop. Rectangle limits
  966.         should be in pixels regardless of screen mode.
  967.  
  968. Return Value:    None.
  969.  
  970. -----------------------------------------------------------------------
  971. Mouse::InstallHandler()
  972.  
  973. Syntax:     void InstallHandler(unsigned mask,
  974.                     void interrupt (*fn)(void))
  975.  
  976. Description:    Installs an interrupt handler function. This function
  977.         is automatically run whenever an event occurs that is
  978.         included in the mask. The mouse driver loads the CPU
  979.         registers with mouse information before calling the
  980.         function. Therefore, the first action should be to save
  981.         this information to an event buffer, which can be accom-
  982.         plished by calling the Save() function. The remaining
  983.         function code should be kept to a minimum, and the func-
  984.         tion MUST be terminated with the EventExit() macro. The
  985.         mask bits are described in Table X. If a function poin-
  986.         ter is not passed in the parameter list, then the de-
  987.         fault handler MouseHandler() will be used.
  988.  
  989. Return Value:    None.
  990.  
  991. -----------------------------------------------------------------------
  992. Mouse::Save()
  993.  
  994. Syntax:     void Save(int event, int button, int x, int y,
  995.               int xcount, int ycount)
  996.  
  997. Description:    Stores the passed parameters in the event buffer. This
  998.         should be the first function called from an event hand-
  999.         ler routine. See the default handler MouseHandler() for
  1000.         details.
  1001.  
  1002. Return Value:    None.
  1003.  
  1004. -----------------------------------------------------------------------
  1005. Mouse::GetEvent
  1006.  
  1007. Syntax:     void GetEvent(void)
  1008.  
  1009. Description:    Gets the next event from the event buffer and loads the
  1010.         parameters into class variables.
  1011.  
  1012. Return Value:    None.
  1013.  
  1014. -----------------------------------------------------------------------
  1015. Mouse::ClearEvent
  1016.  
  1017. Syntax:     void ClearEvent(void)
  1018.  
  1019. Description:    Clears the current event from the internal class varia-
  1020.         bles.
  1021.  
  1022. Return Value:    None.
  1023.  
  1024. -----------------------------------------------------------------------
  1025. Mouse::ClearBuffer()
  1026.  
  1027. Syntax:     void ClearBuffer(void)
  1028.  
  1029. Description:    Clears the event buffer.
  1030.  
  1031. Return Value:    None.
  1032.  
  1033. -----------------------------------------------------------------------
  1034.  
  1035. References
  1036. 1.  Kent Porter, "Mouse Mysteries, Part I: Text", Turbo 
  1037.     Technix, Vol. 1, No. 4, pp. 52-67, May/June 1988.
  1038. 2.  Kent Porter, "Mouse Mysteries, Part II: Graphics", Turbo 
  1039.     Technix, Vol. 1, No. 5, pp. 42-53, July/August 1988.
  1040. 3.  Terry Dettmann, DOS Programmers Reference, Part V: 
  1041.     Reference, Mouse Functions, pp. 717-739, Que, 1989.
  1042. 4.  Ralf Brown, Interrupt List, Release 90.3, July 15, 1990.  
  1043.     This is available on the Public Domain as INTER390.
  1044.